package com.bsg.upm.service;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bsg.upm.constant.DictConstants;
import com.bsg.upm.constant.DictTypeConstants;
import com.bsg.upm.constant.SysConstants;
import com.bsg.upm.dto.SubServDto;
import com.bsg.upm.dto.UnitDto;
import com.bsg.upm.entity.DefinitionSubServArchEntity;
import com.bsg.upm.entity.DefinitionSubServEntity;
import com.bsg.upm.entity.DefinitionSubServUnitScaleEntity;
import com.bsg.upm.entity.ServEntity;
import com.bsg.upm.entity.SiteEntity;
import com.bsg.upm.entity.SubOrderEntity;
import com.bsg.upm.entity.SubServEntity;
import com.bsg.upm.entity.SubServSoftwareImageEntity;
import com.bsg.upm.exception.APIException;
import com.bsg.upm.http.RespJson;
import com.bsg.upm.http.RespJsonFactory;

/**
 * 子服务管理业务处理类
 * 
 * @author HCK
 *
 */
@Service
public class SubServService extends BaseService {

	@Resource
	private MonitorSubServService monitorSubServService;

	@Resource
	private UnitService unitService;

	/**
	 * 获取指定服务下的指定类型子服务
	 * 
	 * @param servId
	 *            服务编码
	 * @param subServType
	 *            子服务类型
	 * @return RespJson请求结果对象
	 * @throws APIException
	 *             API异常处理类
	 */
	public RespJson list(String servId, String subServType) throws APIException {
		try {
			JSONArray results = new JSONArray();
			// 获取指定的服务
			ServEntity serv = servDao.get(servId);
			if (serv == null) {
				return RespJsonFactory.build(HttpStatus.SC_GONE, "该服务不存在");
			}

			// 站点
			SiteEntity site = serv.getOrder().getArea().getSite();

			// 子服务类型
			List<String> subServTypes = new ArrayList<>();
			subServTypes.add(subServType);

			// 从MGM获取指定类型的服务信息
			JSONArray mgmServInfos = listServInfosFromMGM(site.getId(), subServTypes);

			// horus服务状态信息
			Map<String, JSONArray> monitorUnitStatusMap = new HashMap<>();
			try {
				// 从horus获取指定类型的监控信息
				monitorUnitStatusMap = monitorSubServService.getAllSubServStatusByType(site.getId(), subServType);
			} catch (APIException e) {
			}

			// 服务的拓扑信息
			JSONObject topologyInfo = null;
			try {
				topologyInfo = getTopology(serv);
			} catch (Exception e) {
			}

			List<SubServEntity> subServs = serv.getSubServs();
			for (SubServEntity subServ : subServs) {
				String dfSubServType = subServ.getSubOrder().getDefinitionSubServ().getName();
				if (dfSubServType.equals(subServType)) {

					SubServDto subServDto = buildBaseShowDto(subServ);

					JSONObject mgmServInfo = null;
					JSONArray monitorUnitInfos = null;
					if (StringUtils.isNotBlank(subServ.getRelateId())) {
						mgmServInfo = findServInfoFromMGM(mgmServInfos, subServ.getRelateId());
						monitorUnitInfos = monitorUnitStatusMap.get(subServ.getRelateId());
					}
					setMgmServShow(subServDto, mgmServInfo);

					setMonitorUnitShow(subServDto, monitorUnitInfos,
							subServ.getSubOrder().getDefinitionSubServArch().getUnitNum());

					List<UnitDto> unitsDto = unitService.buildUnitDtos(subServ, mgmServInfo, monitorUnitInfos,
							topologyInfo);
					subServDto.setUnits(unitsDto);

					results.add(subServDto);
				}
			}
			return RespJsonFactory.buildOK(results);
		} catch (Exception e) {
			logger.error("子服务查询异常", e);
			throw new APIException("子服务查询异常:" + e.getMessage());
		}
	}

	/**
	 * 从MGM获取指定类型的所有服务信息
	 * 
	 * @param siteId
	 *            站点编码信息
	 * @param subServTypes
	 *            类型集合
	 * @return MGM服务信息
	 * @throws APIException
	 *             API异常处理类
	 */
	public JSONArray listServInfosFromMGM(String siteId, List<String> subServTypes) throws APIException {
		String urlPattern = "/{0}/services";
		if (subServTypes != null && subServTypes.size() != 0) {
			urlPattern += "?image_name=" + StringUtils.join(subServTypes, ",");
		}
		String url = MessageFormat.format(urlPattern, SysConstants.MGM_VERSION);
		RespJson httpRespJson = sendHttpGet(siteId, SysConstants.INTERFACE_TYPE_MGM, url);
		if (httpRespJson.getStatus() == HttpStatus.SC_OK) {
			return ((JSONArray) httpRespJson.getData());
		} else {
			throw new APIException(httpRespJson.getMsg());
		}
	}

	/**
	 * 获取子服务状态 <br>
	 * 1.MGM单元个数和horus单元监控个数不一致时，子服务状态为未知。 <br>
	 * 2.horus所有单元状态全是passing时，子服务状态为passing。 <br>
	 * 3.horus所有单元状态全是为null时，子服务状态为未知。 <br>
	 * 4.horus所有单元状态为null和critical时，子服务状态为critical。 <br>
	 * 5.其他情况时，子服务状态为warning。
	 * 
	 * @param unitCnt
	 *            单元个数
	 * @param monitorUnitsStatus
	 *            单元状态集合
	 * @return 子服务状态
	 */
	public String getSubServStatus(int unitCnt, JSONArray monitorUnitsStatus) {
		String subServStatus = DictConstants.SUBSERV_STATUS_UNKNOWN;
		int passingCnt = 0;
		int criticalCnt = 0;
		int unknownCnt = 0;
		if (monitorUnitsStatus != null) {
			if (unitCnt != monitorUnitsStatus.size()) {
				return DictConstants.SUBSERV_STATUS_UNKNOWN;
			}
			for (int m = 0; m < unitCnt; m++) {
				JSONObject unitMonitorJsonObj = monitorUnitsStatus.getJSONObject(m);
				String unitStatus = unitMonitorJsonObj.getString("value");
				if (unitStatus == null) {
					unknownCnt++;
				} else {
					if (DictConstants.UNIT_STATUS_CRITICAL.equals(unitStatus)) {
						criticalCnt++;
					} else if (DictConstants.UNIT_STATUS_PASSING.equals(unitStatus)) {
						passingCnt++;
					}
				}
			}

			if (passingCnt == unitCnt) {
				subServStatus = DictConstants.SUBSERV_STATUS_PASSING;
			} else if (unknownCnt == unitCnt) {
				subServStatus = DictConstants.SUBSERV_STATUS_UNKNOWN;
			} else if (criticalCnt + unknownCnt == unitCnt) {
				subServStatus = DictConstants.SUBSERV_STATUS_CRITICAL;
			} else {
				subServStatus = DictConstants.SUBSERV_STATUS_WARNNING;
			}
		}
		return subServStatus;
	}

	public List<SubServDto> buildSubServsDto(ServEntity serv, JSONArray mgmServInfos,
			Map<String, JSONArray> monitorUnitStatusMap, JSONObject topologyInfo) {
		SiteEntity site = serv.getOrder().getArea().getSite();

		List<SubServEntity> subServs = serv.getSubServs();
		List<SubServDto> subServsDto = new ArrayList<>(subServs.size());
		for (SubServEntity subServ : subServs) {

			SubServDto subServDto = buildBaseShowDto(subServ);

			JSONObject mgmServInfo = null;
			JSONArray monitorUnitInfos = null;
			if (StringUtils.isNotBlank(subServ.getRelateId())) {
				mgmServInfo = findServInfoFromMGM(mgmServInfos, subServ.getRelateId());
				monitorUnitInfos = monitorUnitStatusMap.get(subServ.getRelateId());
			}
			setMgmServShow(subServDto, mgmServInfo);

			setMonitorUnitShow(subServDto, monitorUnitInfos,
					subServ.getSubOrder().getDefinitionSubServArch().getUnitNum());

			List<UnitDto> unitsDto = unitService.buildUnitDtos(subServ, mgmServInfo, monitorUnitInfos, null);

			for (UnitDto unitDto : unitsDto) {
				unitDto.setSiteId(site.getId());
				unitDto.setSiteName(site.getName());

				if (topologyInfo != null) {
					String defitionServCode = serv.getOrder().getDefinitionServ().getCode();
					if (SysConstants.SERV_UPSQL_UPPROXY_SWM_CODE.equals(defitionServCode)) {
						JSONObject datanodeGroupInfo = topologyInfo.getJSONObject("datanode_group");
						if (datanodeGroupInfo != null) {
							JSONObject swmServInfo = datanodeGroupInfo.getJSONObject(subServ.getRelateId());
							if (swmServInfo != null) {
								JSONObject swmUnitInfo = swmServInfo.getJSONObject(unitDto.getRelateName());
								if (swmUnitInfo != null) {
									unitDto.setRole(swmUnitInfo.getString("type"));
									unitDto.setAvailableStatus(swmUnitInfo.getString("status"));
								}
							}
						}
					} else if (SysConstants.SERV_UPREDIS_URPROXY_SENTINEL_CODE.equals(defitionServCode)) {
						JSONArray roleInfos = topologyInfo.getJSONArray(subServ.getRelateId());
						if (roleInfos != null) {
							for (int i = 0; i < roleInfos.size(); i++) {
								unitDto.setRole(roleInfos.getJSONObject(i).getString("value"));
							}
						}
					}
				}
			}
			subServDto.setUnits(unitsDto);

			subServsDto.add(subServDto);
		}
		return subServsDto;
	}

	private SubServDto buildBaseShowDto(SubServEntity subServ) {
		SubServDto subServDto = new SubServDto();
		subServDto.setId(subServ.getId());
		SubOrderEntity subOrder = subServ.getSubOrder();
		DefinitionSubServEntity dfSubServ = subOrder.getDefinitionSubServ();
		// 类型
		subServDto.setType(dfSubServ.getName());
		// 关联MGM编码
		subServDto.setRelateId(subServ.getRelateId());
		// 数据目录类型
		subServDto.setDateDirType(subOrder.getDataDirDeviceType());
		subServDto.setDateDirTypeText(
				dictTypeCache.getTextFromCache(DictTypeConstants.DATA_DIR_TYPE, subOrder.getDataDirDeviceType()));

		// 日志目录类型
		subServDto.setLogDirType(subOrder.getLogDirDeviceType());
		subServDto.setLogDirTypeText(
				dictTypeCache.getTextFromCache(DictTypeConstants.LOG_DIR_TYPE, subOrder.getLogDirDeviceType()));
		// 所用端口
		subServDto.setPort(subServ.getPort().getPortValue());
		return subServDto;
	}

	private void setMgmServShow(SubServDto subServDto, JSONObject mgmServInfo) {
		if (mgmServInfo != null) {
			JSONObject imageInfo = mgmServInfo.getJSONObject("image");
			if (imageInfo != null) {
				String servType = imageInfo.getString("name");
				// 架构
				JSONObject archInfo = mgmServInfo.getJSONObject("architecture");
				if (archInfo != null) {
					String archCode = archInfo.getString("code");
					String archMode = archInfo.getString("mode");
					DefinitionSubServArchEntity arch = definitionSubServArchCache.getArchFromCache(servType, archCode,
							archMode);
					if (arch != null) {
						subServDto.setArchId(arch.getId());
						subServDto.setArchName(arch.getName());
					}
				}

				JSONObject unitRequireInfo = mgmServInfo.getJSONObject("unit_require");
				if (unitRequireInfo != null) {
					// 规模
					JSONObject requireInfo = unitRequireInfo.getJSONObject("require");
					if (requireInfo != null) {
						int cpu = requireInfo.getIntValue("ncpu");
						long mem = requireInfo.getLongValue("memory");
						DefinitionSubServUnitScaleEntity scale = definitionSubServUnitScaleCache
								.getScaleFromCache(servType, cpu, mem);
						if (scale != null) {
							subServDto.setScaleId(scale.getId());
							subServDto.setScaleName(scale.getName());
						}
					}
				}

				SubServSoftwareImageEntity image = subServSoftwareImageDao.getByRelateId(imageInfo.getString("id"));
				if (image != null) {
					subServDto.setSoftwareImageId(image.getId());
					String softwareVersion = getSoftwareImageNameAndVersion(image);
					subServDto.setSoftwareVersion(softwareVersion);
				}

				// 数据目录大小
				Long dateSize = null;
				// 日志目录大小
				Long logSize = null;
				JSONArray volumeInfos = unitRequireInfo.getJSONArray("volumes");
				for (int i = 0; i < volumeInfos.size(); i++) {
					JSONObject volumeInfo = volumeInfos.getJSONObject(i);
					if (volumeInfo.getString("name").equals("DAT")) {
						dateSize = volumeInfo.getLong("size");
					} else if (volumeInfo.getString("name").equals("LOG")) {
						logSize = volumeInfo.getLong("size");
					}
				}
				subServDto.setDateSize(dateSize);
				subServDto.setLogSize(logSize);

				JSONArray networkInfos = unitRequireInfo.getJSONArray("networks");
				if (networkInfos != null && networkInfos.size() > 0) {
					subServDto.setNetworkBandwidth(networkInfos.getJSONObject(0).getIntValue("bandwidth"));
				}

				// 接入点
				List<String> endPointIps = new ArrayList<>();
				JSONArray unitInfos = mgmServInfo.getJSONArray("units");
				if (unitInfos != null) {
					for (int i = 0; i < unitInfos.size(); i++) {
						JSONObject unitInfo = unitInfos.getJSONObject(i);
						JSONArray networkingInfos = unitInfo.getJSONArray("networkings");
						if (networkingInfos != null && networkingInfos.size() != 0) {
							JSONObject networkingInfo = networkingInfos.getJSONObject(0);
							endPointIps.add(networkingInfo.getString("ip_addr"));
						}
					}
				}
				subServDto.setEndPointIps(endPointIps);
			}

			subServDto.setBackupFileSumSize(mgmServInfo.getLongValue("backup_file_sum"));
		}
	}

	private void setMonitorUnitShow(SubServDto subServDto, JSONArray monitorUnitsStatus, int unitSum) {
		// 状态
		String status = getSubServStatus(unitSum, monitorUnitsStatus);
		subServDto.setStatus(status);
		subServDto.setStatusText(dictTypeCache.getTextFromCache(DictTypeConstants.SUBSERV_STATUS, status));
	}

	private JSONObject findServInfoFromMGM(JSONArray mgmServInfos, String mgmServId) {
		for (int i = 0; i < mgmServInfos.size(); i++) {
			JSONObject mgmServInfo = mgmServInfos.getJSONObject(i);
			if (mgmServInfo.getString("id").equals(mgmServId)) {
				return mgmServInfo;
			}
		}
		return null;
	}

}
